﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Management;
using System.Text;
using System.Timers;
using WindowsStateService.Data;

namespace WindowsStateService.Manager
{
    public class SerialPortService
    {
        private string[] portNames;
        private static SerialPortService _instance;
        private IList<PortInfo> portInfos;
        private Dictionary<SerialPort, ulong> com_received_dic;
        private Dictionary<SerialPort, ulong> com_send_dic;
        private IList<SerialPort> serialPorts;
        private IList<Timer> timers;
        //  public EventHandler<>

        public static SerialPortService Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new SerialPortService();
                }
                return _instance;
            }
        }

        public SerialPortService()
        {
            portInfos = new List<PortInfo>();
            portNames = SerialPort.GetPortNames();
            com_received_dic = new Dictionary<SerialPort, ulong>();
            com_send_dic = new Dictionary<SerialPort, ulong>();
            serialPorts = new List<SerialPort>();
            timers = new List<Timer>(); 
            foreach (var name in portNames)
            {
                var serialPort = new SerialPort(name);
                serialPorts.Add(serialPort);
                PortInfo info = new PortInfo();
                info.Name = name;
                info.BaudRate = serialPort.BaudRate;
                info.DataBits = serialPort.DataBits;
                info.Parity = serialPort.Parity;
                info.StopBits = serialPort.StopBits;
                //Debugger.Launch();
                InitializePortInfo(info);
                com_received_dic.Add(serialPort, 0);
                com_send_dic.Add(serialPort, 0);
                portInfos.Add(info);
            }
        }

        public void SaveSerialPortInfo()
        {
            using (FileStream fs = new FileStream(CommonPath.SerialPortConfigFileName, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
            {
                foreach(var info in portInfos)
                {
                    string jsonString = JsonConvert.SerializeObject(info);
                    byte[] bytes = Encoding.UTF8.GetBytes(jsonString + Environment.NewLine);
                    fs.Write(bytes, 0, bytes.Length);
                }               
            }
        }

        public void StartMonitor()
        {
            foreach (var port in serialPorts)
            {
                port.Open();
                port.DataReceived += OnPortDataReceived;
            }
            foreach(var port in serialPorts)
            {
                SerialPort p = port;
                Timer tr = new Timer();
                tr.Interval = 1000 * 60 * 4;
                tr.Elapsed += (s, e)=>{
                    lock (com_received_dic)
                    {
                        if (com_received_dic.TryGetValue(p, out ulong received_datas))
                        {
                            DataBase data = new DataBase(received_datas);
                            WriteToMonitorFile(data, CommonPath.GetReceivedPackageDatasFile(p.PortName));
                            com_received_dic[p] = 0;
                        }
                    }
                    //if (com_send_dic.TryGetValue(p, out ulong send_datas))
                    //{
                    //    DataBase data = new DataBase(send_datas);
                    //    WriteToMonitorFile(data, CommonPath.GetSendPackageDatasFile(p.PortName));
                    //}
                };
                timers.Add(tr);
                tr.Start();
            }
        }

        public void Disposed()
        {
            foreach (var port in serialPorts)
            {
                port.Close();
                port.DataReceived -= OnPortDataReceived;
            }
            foreach(var t in timers)
            {
                t.Stop();
            }
        }

        private void OnPortDataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            SerialPort sp = (SerialPort)sender;
            ulong bytesToRead = (ulong)(sp.BytesToRead);
            lock (com_received_dic)
            {
                if (com_received_dic.TryGetValue(sp, out ulong pre_value))
                {
                    ulong total_bytes = pre_value + bytesToRead;
                    com_received_dic.Add(sp, total_bytes);
                }
            }
        }

        private void InitializePortInfo(PortInfo info)
        {
            try
            {
                string query = "SELECT * FROM Win32_PnPEntity WHERE Name LIKE '%({0})%'";

                // 创建 ManagementObjectSearcher 对象
                using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2", string.Format(query, info.Name)))
                {
                    // 执行查询
                    foreach (ManagementObject queryObj in searcher.Get())
                    {
                        // 输出属性信息
                        info.Manufacturer = queryObj.Properties["Manufacturer"].Value.ToString();
                        info.Caption = queryObj.Properties["Caption"].Value.ToString();
                        info.Description = queryObj.Properties["Description"].Value.ToString();
                    }
                }
            }catch(Exception ex)
            {
                ServiceLogManager.Instance.Debug(ex.StackTrace);
            }
        }

        public IList<string> PortNames()
        {
            return new List<string>(SerialPort.GetPortNames());
        }

        private void WriteToMonitorFile(DataBase data, string fileName)
        {
            if (data == null)
            {
                return;
            }
            string dataFile = fileName;
            try
            {
                using (FileStream fs = new FileStream(dataFile, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
                {
                    string data_str = JsonConvert.SerializeObject(data);
                    byte[] bytes = Encoding.UTF8.GetBytes(data_str + Environment.NewLine);
                    fs.Write(bytes, 0, bytes.Length);
                }
            }
            catch (Exception ex) 
            {
                ServiceLogManager.Instance.Debug($"SerialPortService error! {ex.Message}{ex.StackTrace}");
            }
        }
    }
}
